// Package supermarket 超市
package supermarket

import (
	"context"

	"shop-manager/internal/do"

	"github.com/samber/lo"
	"gorm.io/gorm"
)

const (
	SupermarketStatusActive   = 1
	SupermarketStatusInactive = 2
)

const (
	MaxPageSize     = 100
	DefaultPageSize = 10
)

//go:generate newc
type SupermarketRepo struct {
	db *gorm.DB
}

// 保持两个参数, 统一处理
func (s *SupermarketRepo) Create(ctx context.Context, supermarket *do.Supermarket) (_ any, err error) {
	supermarket.Status = SupermarketStatusActive
	err = s.db.WithContext(ctx).Create(supermarket).Error
	return supermarket.ID, err
}

// 只限部分字段可修改, 其余字段不允许修改
func (s *SupermarketRepo) Update(ctx context.Context, supermarket *do.Supermarket) (err error) {
	origin := &do.Supermarket{}
	if err := s.db.WithContext(ctx).First(origin, supermarket.ID).Error; err != nil {
		return err
	}

	origin.Name = supermarket.Name
	origin.Contact = supermarket.Contact
	origin.Status = supermarket.Status

	return s.db.WithContext(ctx).Save(origin).Error
}

type ListParam struct {
	Page     int
	PageSize int

	IDs    []int  // 指定ID列表
	Status int    // 0不限制, 1合作中, 2已解约
	Search string // 模糊搜索
	// 排序, 格式为 field [ASC/DESC], ...
	Sorts string
}

func (s *SupermarketRepo) List(ctx context.Context, param ListParam) (listData []*do.Supermarket, total int64, err error) {
	if param.Page <= 0 {
		param.Page = 1
	}
	if param.PageSize == 0 { // -1 means no limit
		param.PageSize = DefaultPageSize
	}
	if param.PageSize > MaxPageSize {
		param.PageSize = MaxPageSize
	}

	err = s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if len(param.IDs) > 0 {
			tx = tx.Where("id IN ?", param.IDs)
		}
		if param.Status != 0 {
			tx = tx.Where("status = ?", param.Status)
		}
		if param.Search != "" {
			tx = tx.Where("name LIKE ?", "%"+param.Search+"%")
		}
		if param.Sorts != "" {
			tx = tx.Order(param.Sorts)
		}

		err = tx.Model(&do.Supermarket{}).Find(&listData).Count(&total).Error
		if err != nil {
			return err
		}

		offset := (param.Page - 1) * param.PageSize
		err = tx.Model(&do.Supermarket{}).
			Offset(offset).
			Limit(param.PageSize).
			Find(&listData).Error
		if err != nil {
			return err
		}

		return err
	})
	return listData, total, err
}

func (s *SupermarketRepo) GetSupermarketMap(ctx context.Context, param ListParam) (m map[int]*do.Supermarket, err error) {
	listData, _, err := s.List(ctx, param)
	if err != nil {
		return nil, err
	}

	return lo.Associate(listData, func(item *do.Supermarket) (int, *do.Supermarket) {
		return item.ID, item
	}), nil
}
